﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace Netfraction.Managers
{
    public delegate void DownloadEventHandler(DownloadEventArgs e);
    public delegate void FileListDownloadEventHandler(FileListDownloadEventArgs e);

    public class DownloadEventArgs : EventArgs
    {
        public System.IO.MemoryStream Stream { get; set; }
        public RemoteMachine.Peer Peer { get; set; }

        public DownloadEventArgs(System.IO.MemoryStream memStream, RemoteMachine.Peer peer)
        {
            this.Peer = peer;
            this.Stream = memStream;
        }
    }

    public class FileListDownloadEventArgs : EventArgs
    {
        public FileListDownloadEventArgs(System.Xml.Linq.XDocument xDoc, RemoteMachine.Peer peer)
        {
            this.Peer = peer;
            this.XmlDocument = xDoc;
        }

        public System.Xml.Linq.XDocument XmlDocument { get; set; }
        public RemoteMachine.Peer Peer { get; set; }
    }

    public class DownloadManager
    {
        #region Singleton Pattern
        // Use singleton pattern.
        private static DownloadManager _instance;

        /// <summary>
        /// Obtain singleton instance of Client
        /// </summary>
        /// <returns></returns>
        public static DownloadManager GetInstance()
        {
            // Check instance
            if (DownloadManager._instance == null)
            {
                // Initialize instance
                DownloadManager._instance = new DownloadManager();
            }

            // Return instance
            return DownloadManager._instance;
        }
        #endregion Singleton Pattern

        public static event DownloadEventHandler OnDownloadCompleted;
        public static event FileListDownloadEventHandler OnFileListDownloaded;

        public static void DownloadCompleted(System.IO.MemoryStream fStream, RemoteMachine.Peer peer)
        {
            if (OnDownloadCompleted != null)
                OnDownloadCompleted(new DownloadEventArgs(fStream, peer));
        }

        public static void FileListDownloaded(System.Xml.Linq.XDocument xDoc, RemoteMachine.Peer peer)
        {
            if (OnFileListDownloaded != null)
                OnFileListDownloaded(new FileListDownloadEventArgs(xDoc, peer));
        }


        public DownloadManager()
        {
            PeerManager.OnPeerConnectionHandshakeComplete += new PeerEventHandler(PeerManager_OnPeerConnectionHandshakeComplete);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification="Message DCTM must be sent to the hub node.")]
        public void GetFileList(RemoteMachine.Hub hub, Identity remoteIdentity)
        {
            RemoteMachine.Peer remPeer = PeerManager.GetInstance()[remoteIdentity.ClientId];
            if (remPeer == null)
                return;

            if (remPeer.Connection.State == Netfraction.RemoteMachine.ConnectionState.Disconnected)
            {
                //remPeer.Connection.Connect(new System.Net.IPEndPoint(remoteIdentity.IPv4Address, remoteIdentity.Udp4Port)); ;
                Network.Protocol.ProtocolMessageFactory factory = new Network.Protocol.BASE.Factory.FactoryCTM();

                Dictionary<int, object> factoryParams = new Dictionary<int, object>();

                factoryParams.Add((int)Network.Protocol.BASE.Factory.CTMParameterOptions.SessionId, hub.SessionId);
                factoryParams.Add((int)Network.Protocol.BASE.Factory.CTMParameterOptions.TargetId, remPeer.SessionId);
                factoryParams.Add((int)Network.Protocol.BASE.Factory.CTMParameterOptions.Protocol, "ADC/1.0");
                factoryParams.Add((int)Network.Protocol.BASE.Factory.CTMParameterOptions.Port, "53168");
                factoryParams.Add((int)Network.Protocol.BASE.Factory.CTMParameterOptions.Token, "afmnls395u0");

                OnDownloadCompleted += new DownloadEventHandler(DownloadManager_OnDownloadCompleted);
                hub.Connection.Send(factory.Create(Network.Protocol.ProtocolMessage.MessageTypeEnum.Direct, factoryParams).ToString());
                (remPeer.Connection as RemoteMachine.PeerConnection).Listen(hub.Connection.LocalEndPoint.Address, 53168);
            }
            else
            {
                PeerManager_OnPeerConnectionHandshakeComplete(new Netfraction.RemoteMachine.PeerEventArgs(remPeer));
            }
        }

        void DownloadManager_OnDownloadCompleted(DownloadEventArgs e)
        {
            Console.WriteLine(e.Stream.Length);

            System.IO.MemoryStream outStream = ShareManager.ShareManager.GetInstance().ReadFileListFromStream("files.xml.bz2", e.Stream);
            Console.WriteLine(outStream.Length);

            XDocument xDoc = XDocument.Load(XmlReader.Create(outStream));
            OnFileListDownloaded(new FileListDownloadEventArgs(xDoc, e.Peer));
        }

        void PeerManager_OnPeerConnectionHandshakeComplete(Netfraction.RemoteMachine.PeerEventArgs args)
        {
            Network.Protocol.ProtocolMessageFactory factory = new Network.Protocol.BASE.Factory.FactoryGET();

            Dictionary<int, object> factoryParams = new Dictionary<int, object>();

            factoryParams.Add((int)Network.Protocol.BASE.Factory.GETParameterOptions.Type, Network.Protocol.BASE.Factory.GETTypes.File);
            factoryParams.Add((int)Network.Protocol.BASE.Factory.GETParameterOptions.Identifier, "files.xml.bz2");
            factoryParams.Add((int)Network.Protocol.BASE.Factory.GETParameterOptions.StartPosition, "0");
            factoryParams.Add((int)Network.Protocol.BASE.Factory.GETParameterOptions.BytesToReceive, "-1");

            args.Peer.Connection.Send(factory.Create(Network.Protocol.ProtocolMessage.MessageTypeEnum.Client, factoryParams).ToString());
        }
    }
}
